package com.lube;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.lube.codec.CommandType;
import com.lube.codec.Message;
import com.lube.protobuf.ConnectProtos.Connect;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;

/**
 * 业务处理
 * 
 * @author caizhiping
 * @date 2017年2月9日 下午2:27:47
 */
public class ClientHandler extends SimpleChannelInboundHandler<Message> {

	private static final Logger LOG = LogManager.getLogger(ClientHandler.class);

	private final static String CLIENT_ID = "Test_001";
	private final static String USERNAME = "nike";
	private final static String PASSWORD = "S6a00@12";

	/**
	 * 记录心跳请求次数，如果心跳请求3次收不到回应，把连接断掉
	 */
	private int pingTimes;

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
		LOG.info(msg.getCommandType());

		try {
			CommandType commandType = msg.getCommandType();
			switch (commandType) {
			case PINGACK:
				pingTimes = 0;
				return;
			}
		} catch (Throwable e) {
			LOG.error(e);
		}
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		connect(ctx.channel());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		ctx.channel().close();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		ctx.channel().close();

		LOG.error(cause);
	}

	private void connect(Channel channel) {
		Connect connect = Connect.newBuilder().setClientId(CLIENT_ID).setUserName(USERNAME).setPassword(PASSWORD)
				.build();

		Message msg = new Message(CommandType.CONNECT, connect.toByteArray().length, connect);

		channel.writeAndFlush(msg);
	}

	/**
	 * 利用写空闲发送心跳检测消息
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent e = (IdleStateEvent) evt;
			switch (e.state()) {
			case WRITER_IDLE:
				if (pingTimes >= 3) {
					ctx.close();

					LOG.warn("服务端没有回应心跳关闭连接,pingTime=" + pingTimes);

					pingTimes = 0;
				} else {
					ctx.channel().writeAndFlush(new Message(CommandType.PING, 0, null));
					LOG.info("向服务端发送心跳请求,pingTime=" + pingTimes);
					pingTimes++;
				}

				break;

			default:
				break;
			}
		}
	}
}
